/**
 * Copyright (c) 2009, Gareth Bond, http://www.gazbond.co.uk
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
 * that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *     following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
 *     the following disclaimer in the documentation and/or other materials provided with the distribution.
 *   * Neither the name of Yii Software LLC nor the names of its contributors may be used to endorse or
 *     promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * AutoAjax is a Javascript object used to automatically add AJAX style functionality to web pages that have
 * been generated using a 'two step view' system such as with Zend MVC layouts.
 *
 * An area of a page is marked as an 'AJAX controller container' using a css selector and then hyperlinks and
 * forms within this container are marked as 'AJAX links' and "AJAX forms' again using css selectors.
 *
 * Hyperlink clicks and form submits are then handled by AutoAjax asynchronously and the response inserted
 * into the correct part of the page with out a page refresh.
 *
 * This requires that any layouts used are turned off during an AJAX request which when using Zend MVC can be
 * achieved by adding the AutoAjaxPlugin to the Zend MVC front controller.
 * 
 * AutoAjax uses jQuery for its operations so this must be included on a page before AutoAjax can function.
 * 
 * @author Gareth Bond
 */
var AutoAjax = {
    /**
     * AJAX controller container selector to use
     */
    _ajaxControllerContainerSelector : '.ajaxControllerContainer',

    /**
     * AJAX link selector to use
     */
    _ajaxLinkSelector : 'a.ajaxLink',

    /**
     * AJAX form selector to use
     */
    _ajaxFormSelector : 'form.ajaxForm',
    
    /**
     * Event handler for AJAX links.
     * Executes an AJAX request using the supplied links 'href' attribute, places the response in to the first
     * AJAX controller container found as a parent of the link and updates the event handling for the container.
     */
    _handleAjaxLink : function(link) {
        var self = this;
        var container = $(link).parents(self._ajaxControllerContainerSelector);
        $.get(link, function(data) {
            container.html(data);
            self._updateAjaxEventHandling(container);
        });
    },

    /**
     * Event handler for AJAX forms.
     * Executes an AJAX request using the supplied forms 'action' attribute as well as the 'names' and 'values'
     * of all contained form elements, places the response in to the first AJAX controller container found as a
     * parent of the form and updates the event handling for the container.
     */
    _handleAjaxForm : function(form) {
        var self = this;
        var container = $(form).parents(self._ajaxControllerContainerSelector);
        var action = $(form).attr('action');
        var postData = {};
        var list = '';
        $('*[name]', form).each(function() {
            var cur = $(this);
            if((cur.attr('type') != 'checkbox' && cur.attr('type') != 'radio') || cur.attr('checked') == true) {
                if(cur.attr('name').charAt(cur.attr('name').length -2) == '[' &&
                    cur.attr('name').charAt(cur.attr('name').length -1) == ']') {
                    if(postData[cur.attr('name')] === undefined) {
                        postData[cur.attr('name')] = [];
                    }
                    postData[cur.attr('name')].push(cur.val());
                }
                else postData[cur.attr('name')] = cur.val();
            }
        });
        $.post(action, postData, function(data) {
            container.html(data);
            self._updateAjaxEventHandling(container);
        });
    },

    /**
     * Updates event handling for the supplied AJAX controller container.
     */
    _updateAjaxEventHandling : function(container) {
        var self = this;
        $(self._ajaxLinkSelector, container).click(function() {
            self._handleAjaxLink(this);
            return false;
        });
        $(self._ajaxFormSelector, container).submit(function() {
            self._handleAjaxForm(this);
            return false;
        });
    },

    /**
     * Adds event handling for the whole page when the page is ready.
     * Searches for all AJAX links and AJAX forms that are within an AJAX controller container and attaches
     * click and submit event handlers to them.
     */
    loadAjaxEventHandling : function() {
        var self = this;
        $(document).ready(function(){
            var format = [self._ajaxControllerContainerSelector, ' ', self._ajaxLinkSelector];
            var selector = format.join('');
            $(selector).click(function() {
                self._handleAjaxLink(this);
                return false;
            });
        });
        $(document).ready(function(){
            var format = [self._ajaxControllerContainerSelector, ' ', self._ajaxFormSelector];
            var selector = format.join('');
            $(selector).submit(function() {
                self._handleAjaxForm(this);
                return false;
            });
        });
    }
};

AutoAjax.loadAjaxEventHandling();